#ifndef DYN_ODE_H
#define DYN_ODE_H

#include "../utilities/dyn_multifunctor.h"

#include <armadillo>

using namespace arma;

/*! \author Joey Dumont <joey.dumont@gmail.com>
 *
 * \date 2012-08-24
 *
 * \brief Abstract class for integrators.
 *
 *
 * This is an abstract class that will
 * define the basic needs of an integration routine.
 * Basic integration variables will be initialized here
 * (system of ODEs to be integrated, initial Conditions,
 * the initial stepsize, the absolute error, relative error,
 * the maximum number of iterations, the minimum stepsize
 * and the maximum stepsize).
 *
 * Other specific variables can be defined in derived
 * classes.
 *
 * The integrands are expected to be in an
 * autonomous dynamical system form, that is
 *  \f{eqnarray}{
 *      y_0' &=& f_0\left(y_0,y_1,\ldots,y_{N-1}\right)  \\
 *      y_1' &=& f_1\left(y_0,y_1,\ldots,y_{N-1}\right)  \\
 *      \ldots
 *  \f}
 */

class ODE
{
public:
    /*! The constructor sets the member
     * variables.
     */
    ODE(MultiFunctor &func,
        colvec _initCond,
        double _start,
        double _end,
        double _initStepsize,
        double _minStepsize=0,
        double _maxStepsize=10,
        double _absTol=0,
        double _relTol=0,
        int _maxIterations=1e6);

    /*! @name Accessor Functions
     * We define the basic accessor functions of
     * this class.
     */
    //@{
    virtual MultiFunctor& getMultiFunctor(){return integrand;}
    virtual colvec getInitCond(){return initCond;}
    virtual double getStart(){return start;}
    virtual double getEnd(){return end;}
    virtual double getInitStepsize(){return initStepsize;}
    virtual double getMinStepsize(){return minStepsize;}
    virtual double getMaxStepsize(){return maxStepsize;}
    virtual double getAbsTol(){return absTol;}
    virtual double getRelTol(){return relTol;}
    virtual int getMaxIterations(){return maxIterations;}
    virtual mat getResults(){return results;}

    virtual void setMultiFunctor(MultiFunctor& _integrand){integrand=_integrand;}
    virtual void setInitCond(colvec _initCond){initCond=_initCond;}
    virtual void setStart(double _start){start=_start;}
    virtual void setEnd(double _end){end=_end;}
    virtual void setInitStepsize(double _initStepsize){initStepsize=_initStepsize;}
    virtual void setMinStepsize(double _minStepsize){minStepsize=_minStepsize;}
    virtual void setMaxStepsize(double _maxStepsize){maxStepsize=_maxStepsize;}
    virtual void setAbsTol(double _absTol){absTol=_absTol;}
    virtual void setRelTol(double _relTol){relTol=_relTol;}
    virtual void setMaxIterations(int _maxIterations){maxIterations=_maxIterations;}
    virtual void setResults(mat _results){results=_results;}
    //@}

    /*! @name Pure Virtual Functions
     * Functions that need to be reimplemented
     * in derived classes. integrate() completes
     * the whole integration routine, while next() computes
     * only one iteration.
     */
    //@{
    /*! We implement a simple integrate() routine
     * for fixed stepsize algorithms. */
    virtual int integrate();
    virtual colvec next(colvec previousStep)=0;
    //@}

protected:
    /*! @name Generic Member Variables
     */
    //@{
    MultiFunctor &integrand;
    colvec initCond;
    double start;
    double end;
    double initStepsize;
    double minStepsize;
    double maxStepsize;
    double absTol;
    double relTol;
    int maxIterations;
    mat results;
    //@}
};

#endif // DYN_ODE_H
